/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFDCHit
  \brief for a DC hit, i.e. a fired sense wire.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-28
  \date 2021-11-30 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-28   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include <cstring>
#include <TGraph.h>
#include "ETFDCHit.h"
#include "ETFMsg.h"
#include "ETFMath.h"
#include "ETFHPTDCCh.h"

using std::cout;
using std::endl;

ETFDCHit::ETFDCHit(){
  Initialize();
} // end ctor

// copy ctor
ETFDCHit::ETFDCHit(const ETFDCHit &t){
  *this = t;
} // end copy ctor
// assignment ctor
ETFDCHit &ETFDCHit::operator=(const ETFDCHit &t){
  if(&t == this) return *this;

  ETFHit::operator=(t);
  fT = t.fT; fR = t.fR; fChi = t.fChi;
  fCh = t.fCh;
  fLayerId = t.fLayerId;
  fWireId = t.fWireId;

  return *this;
} // end member function operator=

ETFDCHit::~ETFDCHit(){}

void ETFDCHit::Initialize(){
  ETFHit::Initialize();
  fCh = nullptr; // need not delete memory - has been taken care of somewhere else
  fT = fR = fChi = -999.;
  fWireId = -1;
  fProj[0] = -9999; fProj[1] = -9999; fProj[2] = -9999;
} // end member function Initialize

const ETFHPTDCCh *ETFDCHit::GetTChannel() const{
  if(!fCh) ETFMsg::Error("ETFHit", "GetTChannel:fCh is nullptr");
  return fCh;
} // end member function GetTChannel

// set fProj
void ETFDCHit::SetProjection(const double *p){
  memcpy(fProj, p, sizeof(fProj));
} // end member function SetProjection

double ETFDCHit::GetProjZ() const{
  if(-999. == fProj[2]) ETFMsg::Error("ETFHit", "GetProjZ: Not assigned");
  return fProj[2];
} // end member function GetProjZ
double ETFDCHit::GetProjX() const{
  if(-999. == fProj[0]) ETFMsg::Error("ETFHit", "GetProjX: Not assigned");
  return fProj[0];
} // end member function GetProjX
void ETFDCHit::GetProjZX(double &z, double &x) const{
  z = GetProjZ();
  x = GetProjX();
} // end member function GetProjZX
void ETFDCHit::GetProjZXR(double &z, double &x, double &r) const{
  if(-999. == fProj[2]) ETFMsg::Error("ETFDCHit", "GetProjZXR: not assigned");
  z = fProj[2]; x = fProj[0]; r = GetR();
} // end member function GetZXR

void ETFDCHit::SetTChannel(const ETFRawChannel *ch){
  fCh = static_cast<const ETFHPTDCCh *>(ch);
  SetFiredStatus(1);
} // end member function SetTChannel

// configure fGHit
void ETFDCHit::ConfigureDraw(){
  ETFHit::ConfigureDraw();

  fGHit->SetMarkerSize(2);
  fGHit->SetMarkerStyle(6);

  EColor c;
  switch(fFiredStatus){
    case 0: c = kBlack; break; // a nullified hit
    case 2: c = kMagenta; break; // belonging to a (regular) trk
    case 3: c = EColor(7); break; // 7: bright blue - associated with a global trk
    default: c = kGreen; break; // default color
  } // end switch
  fGHit->SetMarkerColor(c);

  // draw the drift distance //
  const double r = GetR();
  if(-999. == r) return;

  static const int n = 25;
  const double z = GetProjZ(), x = GetProjX();
  for(int i = 0; i <= n; i++){
    const double t = (2.*i/n-1.)*ETFMath::Pi(); // +- pi
    fGHit->SetPoint(fGHit->GetN(), z+r*cos(t), x+r*sin(t));
  } // end for over i
} // end member function ConfigureDraw

// #define TOTCORR // whether to implement TOT correction to drift time
// t: tot
inline double totcor(double t){ return 3.194492*sqrt(t)-0.0425*t-58.; }
// return true if drift time is new
bool ETFDCHit::SetDriftTimeStart(double time0){
#ifdef TOTCORR
  const double t0t = fCh->tot();
  const double tcorr = fPos[2] > 0. && t0t > 0. ? totcor(t0t) : 0.;
  const double t = fTime - fDelay - time0 + tcorr;
#else
  const double t = fTime - fDelay - time0;
#endif
  if(t == fT) return false; // old time0, ignored
  fT = t; return true;
} // end member function SetDriftTimeStart

// print the hit info
void ETFDCHit::Print(const char *) const{
  ETFHit::Print();
  cout << "Layer Id: " << fLayerId << "      Wire Id: " << fWireId << endl;
  cout << "T: " << fT << " R: " << fR << " chi: " << fChi << endl;
  cout << "Projection(mm): (x, y, z): ";
  cout << "(" << fProj[0] << ", " << fProj[1] << ", " << fProj[2] << ")" << endl;
  GetTChannel()->Print();
} // end member function Print

// assign those member variables that can only be done after all raw data are assigned
void ETFDCHit::Assign(){
  if(!fCh) return;
  fTime = fCh->GetLeadingEdge();
} // end memeber function Assign
